home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / directx / dxf / samples / multimedia / direct3d / optimizedmesh / optimizedmesh.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  19.7 KB  |  559 lines

  1. //-----------------------------------------------------------------------------
  2. // File: OptimizedMesh.cpp
  3. //
  4. // Desc: Sample of optimizing meshes in D3D
  5. //
  6. // Copyright (c) 1998-2000 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <tchar.h>
  10. #include <stdio.h>
  11. #include <windows.h>
  12. #include <commdlg.h>
  13. #include <d3dx8.h>
  14. #include "D3DApp.h"
  15. #include "D3DFont.h"
  16. #include "D3DUtil.h"
  17. #include "DXUtil.h"
  18. #include "resource.h"
  19.  
  20.  
  21.  
  22.  
  23. //-----------------------------------------------------------------------------
  24. // Name: class CMyD3DApplication
  25. // Desc: Main class to run this application. Most functionality is inherited
  26. //       from the CD3DApplication base class.
  27. //-----------------------------------------------------------------------------
  28. class CMyD3DApplication : public CD3DApplication
  29. {
  30.     TCHAR               m_strMeshFilename[512];
  31.     TCHAR               m_strInitialDir[512];
  32.     
  33.     LPD3DXMESH          m_pMesh;              // Local version of mesh, rebuilt on resize
  34.     LPD3DXMESH          m_pMeshOptimized;     // Optimized vid mem mesh, rebuilt on resize
  35.  
  36.     DWORD               m_dwNumMaterials;     // Number of materials
  37.     LPDIRECT3DTEXTURE8* m_pMeshTextures;
  38.     D3DMATERIAL8*       m_pMeshMaterials;
  39.  
  40.     BOOL                m_bShowOptimizedMesh; // Which mesh is currently being drawn
  41.     LPD3DXBUFFER        m_pAdjacencyBuffer;   // Contains the adjaceny info loaded with the mesh
  42.  
  43.     CD3DFont*           m_pFont;              // Font for outputting frame stats
  44.  
  45.     CD3DArcBall         m_ArcBall;            // Mouse rotation utility
  46.     D3DXVECTOR3         m_vObjectCenter;      // Center of bounding sphere of object
  47.     FLOAT               m_fObjectRadius;      // Radius of bounding sphere of object
  48.  
  49.     D3DXMATRIX          m_matWorld;
  50.     DWORD               m_cObjectsPerSide;    // sqrt of the number of objects to draw
  51.  
  52. public:
  53.     HRESULT OneTimeSceneInit();
  54.     HRESULT InitDeviceObjects();
  55.     HRESULT RestoreDeviceObjects();
  56.     HRESULT InvalidateDeviceObjects();
  57.     HRESULT DeleteDeviceObjects();
  58.     HRESULT Render();
  59.     HRESULT FrameMove();
  60.     HRESULT FinalCleanup();
  61.  
  62.     LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  63.     CMyD3DApplication();
  64. };
  65.  
  66.  
  67.  
  68.  
  69. //-----------------------------------------------------------------------------
  70. // Name: WinMain()
  71. // Desc: Entry point to the program. Initializes everything, and goes into a
  72. //       message-processing loop. Idle time is used to render the scene.
  73. //-----------------------------------------------------------------------------
  74. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  75. {
  76.     CMyD3DApplication d3dApp;
  77.  
  78.     if( FAILED( d3dApp.Create( hInst ) ) )
  79.         return 0;
  80.  
  81.     return d3dApp.Run();
  82. }
  83.  
  84.  
  85.  
  86.  
  87. //-----------------------------------------------------------------------------
  88. // Name: CMyD3DApplication()
  89. // Desc: Constructor
  90. //-----------------------------------------------------------------------------
  91. CMyD3DApplication::CMyD3DApplication()
  92. {
  93.     // Override base class members
  94.     m_strWindowTitle     = _T("OptimizedMesh: Optimizing Meshes in D3D");
  95.     m_bUseDepthBuffer    = TRUE;
  96.     m_bShowCursorWhenFullscreen = TRUE;
  97.  
  98.     // Initialize member variables
  99.     m_pMesh         = NULL;
  100.     m_pMeshOptimized     = NULL;
  101.     m_bShowOptimizedMesh = TRUE;
  102.     m_pAdjacencyBuffer   = NULL;
  103.  
  104.     m_dwNumMaterials     = 0L;
  105.     m_pMeshMaterials     = NULL;
  106.  
  107.     m_pFont              = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  108.     
  109.     _tcscpy( m_strInitialDir, DXUtil_GetDXSDKMediaPath() );
  110.     _tcscpy( m_strMeshFilename, _T("knot.x") );
  111.  
  112.     m_cObjectsPerSide = 1;
  113. }
  114.  
  115.  
  116.  
  117.  
  118. //-----------------------------------------------------------------------------
  119. // Name: OneTimeSceneInit()
  120. // Desc: Called during initial app startup, this function performs all the
  121. //       permanent initialization.
  122. //-----------------------------------------------------------------------------
  123. HRESULT CMyD3DApplication::OneTimeSceneInit()
  124. {
  125.     // Set cursor to indicate that user can move the object with the mouse
  126. #ifdef _WIN64
  127.     SetClassLongPtr( m_hWnd, GCLP_HCURSOR, (LONG_PTR)LoadCursor( NULL, IDC_SIZEALL ) );
  128. #else
  129.     SetClassLong( m_hWnd, GCL_HCURSOR, (LONG)LoadCursor( NULL, IDC_SIZEALL ) );
  130. #endif
  131.     return S_OK;
  132. }
  133.  
  134.  
  135.  
  136.  
  137. //-----------------------------------------------------------------------------
  138. // Name: FrameMove()
  139. // Desc: Called once per frame, the call is the entry point for animating
  140. //       the scene.
  141. //-----------------------------------------------------------------------------
  142. HRESULT CMyD3DApplication::FrameMove()
  143. {
  144.     // Setup viewing postion from ArcBall
  145.     D3DXMATRIX matRotationInverse;
  146.     D3DXMATRIX matTemp;
  147.     D3DXMatrixTranslation( &m_matWorld, -m_vObjectCenter.x,
  148.                                       -m_vObjectCenter.y,
  149.                                       -m_vObjectCenter.z );
  150.     D3DXMatrixInverse( &matRotationInverse, NULL, m_ArcBall.GetRotationMatrix() );
  151.     D3DXMatrixMultiply( &m_matWorld, &m_matWorld, &matRotationInverse );
  152.     D3DXMatrixMultiply( &m_matWorld, &m_matWorld, m_ArcBall.GetTranslationMatrix() );
  153.  
  154.     D3DXMatrixTranslation( &matTemp, -m_fObjectRadius  * (m_cObjectsPerSide-1),//* 0.5f,
  155.                                       -m_fObjectRadius * (m_cObjectsPerSide-1),//* 0.5f,
  156.                                       0 );
  157.     D3DXMatrixMultiply( &m_matWorld, &m_matWorld, &matTemp );
  158.  
  159.     D3DXMATRIX matView;
  160.     D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0, 0,-3.7f*m_fObjectRadius * m_cObjectsPerSide),
  161.                                   &D3DXVECTOR3( 0, 0, 0 ),
  162.                                   &D3DXVECTOR3( 0, 1, 0 ) );
  163.     m_pd3dDevice->SetTransform( D3DTS_VIEW,  &matView );
  164.  
  165.     return S_OK;
  166. }
  167.  
  168.  
  169.  
  170. //-----------------------------------------------------------------------------
  171. // Name: Render()
  172. // Desc: Called once per frame, the call is the entry point for 3d
  173. //       rendering. This function sets up render states, clears the
  174. //       viewport, and renders the scene.
  175. //-----------------------------------------------------------------------------
  176. HRESULT CMyD3DApplication::Render()
  177. {
  178.     DWORD xOffset;
  179.     DWORD yOffset;
  180.     D3DXMATRIX matWorld;
  181.     D3DXMATRIX matTemp;
  182.     DWORD cTriangles;
  183.     FLOAT fTrisPerSec;
  184.     TCHAR strInfo[120];
  185.  
  186.     // Clear the scene
  187.     m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
  188.                          0x000000ff, 1.0f, 0x00000000 );
  189.  
  190.     // Draw scene
  191.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  192.     {
  193.         for (xOffset = 0; xOffset < m_cObjectsPerSide; xOffset++)
  194.         {
  195.             for (yOffset = 0; yOffset < m_cObjectsPerSide; yOffset++)
  196.             {
  197.                 D3DXMatrixTranslation( &matTemp, m_fObjectRadius * xOffset * 2,
  198.                                                   m_fObjectRadius * yOffset * 2,
  199.                                                   0 );
  200.                 D3DXMatrixMultiply( &matWorld, &m_matWorld, &matTemp );
  201.                 m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  202.  
  203.  
  204.                 // Set and draw each of the materials in the mesh
  205.                 for( DWORD i=0; i<m_dwNumMaterials; i++ )
  206.                 {
  207.                     m_pd3dDevice->SetMaterial( &m_pMeshMaterials[i] );
  208.                     m_pd3dDevice->SetTexture( 0, m_pMeshTextures[i] );
  209.  
  210.                     // Draw either the optimized or unoptimized mesh
  211.                     if( m_bShowOptimizedMesh )
  212.                         m_pMeshOptimized->DrawSubset( i );
  213.                     else
  214.                         m_pMesh->DrawSubset( i );
  215.                 }
  216.             }
  217.         }
  218.  
  219.         // Calculate and show triangles per sec, a reasonable throughput number
  220.         cTriangles = m_pMesh->GetNumFaces() * m_cObjectsPerSide * m_cObjectsPerSide;
  221.         fTrisPerSec = m_fFPS * cTriangles;
  222.  
  223.         // Output statistics
  224.         wsprintf( strInfo, _T("%s, %ld tris per sec, %ld triangles"),
  225.                   m_bShowOptimizedMesh ? _T("Optimized") : _T("Non-optimized"),
  226.                   (DWORD)fTrisPerSec,
  227.                   cTriangles);
  228.  
  229.         m_pFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
  230.         m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
  231.         m_pFont->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,0), strInfo);
  232.  
  233.  
  234.         m_pd3dDevice->EndScene();
  235.     }
  236.  
  237.     return S_OK;
  238. }
  239.  
  240.  
  241.  
  242.  
  243. //-----------------------------------------------------------------------------
  244. // Name: InitDeviceObjects()
  245. // Desc: Initialize scene objects.
  246. //-----------------------------------------------------------------------------
  247. HRESULT CMyD3DApplication::InitDeviceObjects()
  248. {
  249.     LPDIRECT3DVERTEXBUFFER8 pMeshVB   = NULL;
  250.     LPD3DXBUFFER pD3DXMtrlBuffer = NULL;
  251.     BYTE*        pVertices;
  252.     TCHAR        strMesh[512];
  253.     HRESULT      hr = S_OK;
  254.     BOOL         bNormalsInFile;
  255.     LPD3DXMESH   pMeshTemp;
  256.     LPD3DXMESH   pMeshSysMem = NULL;
  257.     DWORD        *rgdwAdjacencyTemp = NULL;
  258.     DWORD        i;
  259.     D3DXMATERIAL* d3dxMaterials;
  260.     DWORD        dw32Bit;
  261.  
  262.     // Get a path to the media file
  263.     DXUtil_FindMediaFile( strMesh, m_strMeshFilename );
  264.     
  265.     // Load the mesh from the specified file
  266.     hr = D3DXLoadMeshFromX( strMesh, D3DXMESH_SYSTEMMEM, m_pd3dDevice, 
  267.                             &m_pAdjacencyBuffer, &pD3DXMtrlBuffer, 
  268.                             &m_dwNumMaterials, &pMeshSysMem );
  269.     if( FAILED(hr) )
  270.         goto End;
  271.  
  272.     // remember if the mesh is 32 or 16 bit, to be added in on the clones
  273.     dw32Bit = pMeshSysMem->GetOptions() & D3DXMESH_32BIT;
  274.  
  275.     // Get the array of materials out of the returned buffer, and allocate a texture array
  276.     d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
  277.     m_pMeshMaterials = new D3DMATERIAL8[m_dwNumMaterials];
  278.     m_pMeshTextures  = new LPDIRECT3DTEXTURE8[m_dwNumMaterials];
  279.  
  280.     for( i=0; i<m_dwNumMaterials; i++ )
  281.     {
  282.         m_pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
  283.         m_pMeshMaterials[i].Ambient = m_pMeshMaterials[i].Diffuse;
  284.         m_pMeshTextures[i]  = NULL;
  285.  
  286.         // Get a path to the texture
  287.         TCHAR strPath[512];
  288.         DXUtil_FindMediaFile( strPath, d3dxMaterials[i].pTextureFilename );
  289.  
  290.         // Load the texture
  291.         D3DXCreateTextureFromFile( m_pd3dDevice, strPath, &m_pMeshTextures[i] );
  292.     }
  293.  
  294.     // Done with the material buffer
  295.     SAFE_RELEASE( pD3DXMtrlBuffer );
  296.  
  297.     // Lock the vertex buffer, to generate a simple bounding sphere
  298.     hr = pMeshSysMem->GetVertexBuffer( &pMeshVB );
  299.     if( SUCCEEDED(hr) )
  300.     {
  301.         hr = pMeshVB->Lock( 0, 0, &pVertices, D3DLOCK_NOSYSLOCK );
  302.         if( SUCCEEDED(hr) )
  303.         {
  304.             hr = D3DXComputeBoundingSphere( pVertices, pMeshSysMem->GetNumVertices(),
  305.                                             pMeshSysMem->GetFVF(),
  306.                                             &m_vObjectCenter, &m_fObjectRadius );
  307.             pMeshVB->Unlock();
  308.         }
  309.         pMeshVB->Release();
  310.     }
  311.     if( FAILED(hr) )
  312.         goto End;
  313.  
  314.     // Initialize the font 
  315.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  316.  
  317.     // remember if there were normals in the file, before possible clone operation
  318.     bNormalsInFile = pMeshSysMem->GetFVF() & D3DFVF_NORMAL;
  319.  
  320.     // force 32 byte vertices
  321.     if (pMeshSysMem->GetFVF() != (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1))
  322.     {
  323.         hr = pMeshSysMem->CloneMeshFVF( pMeshSysMem->GetOptions(), D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1, 
  324.                                           m_pd3dDevice, &pMeshTemp );
  325.         if( FAILED(hr) )
  326.             goto End;
  327.  
  328.         pMeshSysMem->Release();
  329.         pMeshSysMem = pMeshTemp;
  330.     }
  331.  
  332.  
  333.     // Compute normals for the mesh, if not present
  334.     if (!bNormalsInFile)
  335.     {
  336.         D3DXComputeNormals( pMeshSysMem );
  337.     }
  338.  
  339.     // allocate a second adjacency buffer to store post attribute sorted adjacency
  340.     rgdwAdjacencyTemp = new DWORD[pMeshSysMem->GetNumFaces() * 3];
  341.     if (rgdwAdjacencyTemp == NULL)
  342.     {
  343.         hr = E_OUTOFMEMORY;
  344.         goto End;
  345.     }
  346.  
  347.     // attribute sort - the un-optimized mesh option
  348.     //          remember the adjacency for the vertex cache optimization
  349.     hr = pMeshSysMem->OptimizeInplace( D3DXMESHOPT_COMPACT|D3DXMESHOPT_ATTRSORT,
  350.                                  (DWORD*)m_pAdjacencyBuffer->GetBufferPointer(),
  351.                                  rgdwAdjacencyTemp, NULL, NULL);
  352.     if( FAILED(hr) )
  353.         goto End;
  354.  
  355.     // snapshot the attribute sorted mesh, shown as the un-optimized version
  356.     hr = pMeshSysMem->CloneMeshFVF( dw32Bit|D3DXMESH_MANAGED|D3DXMESH_VB_WRITEONLY, pMeshSysMem->GetFVF(), 
  357.                                       m_pd3dDevice, &m_pMesh );
  358.     if( FAILED(hr) )
  359.         goto End;
  360.  
  361.     // actually do the vertex cache optimization
  362.     hr = pMeshSysMem->OptimizeInplace( D3DXMESHOPT_COMPACT|D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_VERTEXCACHE,
  363.                                  rgdwAdjacencyTemp,
  364.                                  NULL, NULL, NULL);
  365.     if( FAILED(hr) )
  366.         goto End;
  367.  
  368.     // snapshot as the optimized mesh
  369.     hr = pMeshSysMem->CloneMeshFVF( dw32Bit|D3DXMESH_MANAGED|D3DXMESH_VB_WRITEONLY, pMeshSysMem->GetFVF(), 
  370.                                       m_pd3dDevice, &m_pMeshOptimized );
  371.     if( FAILED(hr) )
  372.         goto End;
  373.  
  374.     // check current display setting
  375.     CheckMenuItem( GetMenu(m_hWnd), ID_OPTIONS_DISPLAY1 + (m_cObjectsPerSide-1), MF_CHECKED );
  376.     CheckMenuItem( GetMenu(m_hWnd), IDM_SHOWOPTIMIZEDMESH, m_bShowOptimizedMesh ? MF_CHECKED : MF_UNCHECKED);
  377.  
  378. End:
  379.     SAFE_DELETE_ARRAY( rgdwAdjacencyTemp );
  380.     SAFE_RELEASE( pMeshSysMem );
  381.    
  382.     return hr;
  383. }
  384.  
  385.  
  386.  
  387.  
  388. //-----------------------------------------------------------------------------
  389. // Name: RestoreDeviceObjects()
  390. // Desc: Initialize scene objects.
  391. //-----------------------------------------------------------------------------
  392. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  393. {
  394.     m_pFont->RestoreDeviceObjects();
  395.  
  396.     // Setup render state
  397.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING,     TRUE );
  398.     m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );
  399.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  400.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  401.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  402.  
  403.     // Setup the light
  404.     D3DLIGHT8 light;
  405.     light.Type         = D3DLIGHT_DIRECTIONAL;
  406.     light.Diffuse.r    = light.Diffuse.g  = light.Diffuse.b  = 1.0f;
  407.     light.Specular.r   = light.Specular.g = light.Specular.b = 0.0f;
  408.     light.Ambient.r    = light.Ambient.g  = light.Ambient.b  = 0.3f;
  409.     light.Position     = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  410.     D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &D3DXVECTOR3( 0.3f, -1.0f, 1.0f ) );
  411.     light.Attenuation0 = light.Attenuation1 = light.Attenuation2 = 0.0f;
  412.     light.Range        = sqrtf(FLT_MAX);
  413.     m_pd3dDevice->SetLight(0, &light );
  414.     m_pd3dDevice->LightEnable(0, TRUE );
  415.  
  416.     m_ArcBall.SetWindow( m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height, 0.85f );
  417.     m_ArcBall.SetRadius( m_fObjectRadius );
  418.  
  419.     FLOAT fAspect = m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height;
  420.  
  421.     D3DXMATRIX matProj;
  422.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, m_fObjectRadius/64.0f,
  423.                                 m_fObjectRadius*200.0f);
  424.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  425.  
  426.     return S_OK;
  427. }
  428.  
  429.  
  430.  
  431.  
  432. //-----------------------------------------------------------------------------
  433. // Name: InvalidateDeviceObjects()
  434. // Desc: 
  435. //-----------------------------------------------------------------------------
  436. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  437. {
  438.     m_pFont->InvalidateDeviceObjects();
  439.  
  440.  
  441.     return S_OK;
  442. }
  443.  
  444.  
  445.  
  446.  
  447. //-----------------------------------------------------------------------------
  448. // Name: DeleteDeviceObjects()
  449. // Desc: Called when the app is exiting, or the device is being changed,
  450. //       this function deletes any device dependent objects.
  451. //-----------------------------------------------------------------------------
  452. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  453. {
  454.     m_pFont->DeleteDeviceObjects();
  455.  
  456.     for( UINT i=0; i<m_dwNumMaterials; i++ )
  457.         SAFE_RELEASE( m_pMeshTextures[i] );
  458.     SAFE_DELETE_ARRAY( m_pMeshTextures );
  459.     SAFE_DELETE_ARRAY( m_pMeshMaterials );
  460.     SAFE_RELEASE( m_pAdjacencyBuffer );
  461.     SAFE_RELEASE( m_pMesh );
  462.     SAFE_RELEASE( m_pMeshOptimized );
  463.  
  464.     return S_OK;
  465. }
  466.  
  467.  
  468.  
  469.  
  470. //-----------------------------------------------------------------------------
  471. // Name: FinalCleanup()
  472. // Desc: Called during initial app startup, this function performs all the
  473. //       permanent initialization.
  474. //-----------------------------------------------------------------------------
  475. HRESULT CMyD3DApplication::FinalCleanup()
  476. {
  477.     SAFE_DELETE( m_pFont );
  478.  
  479.     return S_OK;
  480. }
  481.  
  482.  
  483.  
  484.  
  485. //-----------------------------------------------------------------------------
  486. // Name: MsgProc()
  487. // Desc: Message proc function to handle key and menu input
  488. //-----------------------------------------------------------------------------
  489. LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  490.                                     LPARAM lParam )
  491. {
  492.     // Pass mouse messages to the ArcBall so it can build internal matrices
  493.     m_ArcBall.HandleMouseMessages( hWnd, uMsg, wParam, lParam );
  494.  
  495.     // Trap the context menu
  496.     if( WM_CONTEXTMENU==uMsg )
  497.         return 0;
  498.  
  499.     if( uMsg == WM_COMMAND )
  500.     {
  501.         // Toggle mesh optimization
  502.         if( LOWORD(wParam) == IDM_SHOWOPTIMIZEDMESH )
  503.         {
  504.             m_bShowOptimizedMesh = !m_bShowOptimizedMesh;
  505.  
  506.             if( m_bShowOptimizedMesh )
  507.                 CheckMenuItem( GetMenu(hWnd), IDM_SHOWOPTIMIZEDMESH, MF_CHECKED );
  508.             else
  509.                 CheckMenuItem( GetMenu(hWnd), IDM_SHOWOPTIMIZEDMESH, MF_UNCHECKED );
  510.         }
  511.         
  512.  
  513.         // Handle the open file command
  514.         else if( LOWORD(wParam) == IDM_OPENFILE )
  515.         {
  516.             TCHAR g_strFilename[512]   = _T("");
  517.  
  518.             // Display the OpenFileName dialog. Then, try to load the specified file
  519.             OPENFILENAME ofn = { sizeof(OPENFILENAME), NULL, NULL,
  520.                                 _T(".X Files (.x)\0*.x\0\0"), 
  521.                                 NULL, 0, 1, m_strMeshFilename, 512, g_strFilename, 512, 
  522.                                 m_strInitialDir, _T("Open Mesh File"), 
  523.                                 OFN_FILEMUSTEXIST, 0, 1, NULL, 0, NULL, NULL };
  524.  
  525.             if( TRUE == GetOpenFileName( &ofn ) )
  526.             {
  527.                 _tcscpy( m_strInitialDir, m_strMeshFilename );
  528.                 TCHAR* pLastSlash =  _tcsrchr( m_strInitialDir, _T('\\') );
  529.                 if( pLastSlash )
  530.                     *pLastSlash = 0;
  531.                 SetCurrentDirectory( m_strInitialDir );
  532.  
  533.                 // Destroy and recreate everything
  534.                 InvalidateDeviceObjects();
  535.                 DeleteDeviceObjects();
  536.                 InitDeviceObjects();
  537.                 RestoreDeviceObjects();
  538.             }
  539.         }
  540.  
  541.         else if ((LOWORD(wParam) >= ID_OPTIONS_DISPLAY1) && (LOWORD(wParam) <= ID_OPTIONS_DISPLAY36))
  542.         {
  543.             // uncheck old item
  544.             CheckMenuItem( GetMenu(hWnd), ID_OPTIONS_DISPLAY1 + (m_cObjectsPerSide-1), MF_UNCHECKED );
  545.  
  546.             // calc new item
  547.             m_cObjectsPerSide = LOWORD(wParam) - ID_OPTIONS_DISPLAY1 + 1;
  548.  
  549.             // check new item
  550.             CheckMenuItem( GetMenu(hWnd), ID_OPTIONS_DISPLAY1 + (m_cObjectsPerSide-1), MF_CHECKED );
  551.         }
  552.     }
  553.  
  554.     return CD3DApplication::MsgProc( hWnd, uMsg, wParam, lParam );
  555. }
  556.  
  557.  
  558.  
  559.